package com.uziot.activiti.service;

import com.uziot.activiti.entity.VacTask;
import com.uziot.activiti.entity.Vacation;
import com.uziot.activiti.util.ActivitiUtil;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author shidt
 * @version V1.0
 * @className VacationService
 * @date 2021-02-26 10:38:41
 * @description 假期服务
 */


@Slf4j
@Service
public class VacationService {
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IdentityService identityService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    private static final String PROCESS_DEFINE_KEY = "vacationProcess";

    /**
     * 开始请假流程
     *
     * @param userName 用户名
     * @param vac      请假信息包装
     * @return 返回值
     */
    public Object startVac(String userName, Vacation vac) {

        // 设置身份人信息
        identityService.setAuthenticatedUserId(userName);

        // 根据流程ID开始流程
        ProcessInstance vacationInstance
                = runtimeService.startProcessInstanceByKey(PROCESS_DEFINE_KEY);
        // 查询当前任务
        Task currentTask
                = taskService.createTaskQuery()
                .processInstanceId(vacationInstance.getId())
                .singleResult();
        log.info("流程ID:" + vacationInstance.getId());
        // 设置办理人
        taskService.claim(currentTask.getId(), userName);
        // 请假参数
        Map<String, Object> vars = new HashMap<>(4);
        vars.put("applyUser", userName);
        vars.put("days", vac.getDays());
        vars.put("reason", vac.getReason());
        // 执行请假申请流程/推送到下一环节
        taskService.complete(currentTask.getId(), vars);

        return true;
    }

    /**
     * 我正在申请的假
     *
     * @param userName 用户名
     * @return 列表
     */
    public Object myVac(String userName) {
        List<ProcessInstance> instanceList
                = runtimeService.createProcessInstanceQuery()
                .startedBy(userName)
                .list();

        List<Vacation> vacList = new ArrayList<>();
        for (ProcessInstance instance : instanceList) {
            Vacation vac = getVac(instance);
            vacList.add(vac);
        }
        return vacList;
    }

    private Vacation getVac(ProcessInstance instance) {
        Integer days = runtimeService.getVariable(instance.getId(), "days", Integer.class);
        String reason = runtimeService.getVariable(instance.getId(), "reason", String.class);

        Vacation vac = new Vacation();
        vac.setApplyUser(instance.getStartUserId());
        vac.setDays(days);
        vac.setReason(reason);
        // activiti 6 才有
        Date startTime = instance.getStartTime();
        vac.setApplyTime(startTime);
        vac.setApplyStatus(instance.isEnded() ? "申请结束" : "等待审批");
        return vac;
    }

    /**
     * 待我审核的请假
     *
     * @param userName 用户名
     * @return 列表
     */
    public Object myAudit(String userName) {
        List<Task> taskList = taskService.createTaskQuery()
                // 候选用户名字
                .taskCandidateUser(userName)
                // 创建时间排序
                .orderByTaskCreateTime().desc().list();
//        / 多此一举 taskList中包含了以下内容(用户的任务中包含了所在用户组的任务)
//        Group group = identityService.createGroupQuery().groupMember(userName).singleResult();
//        List<Task> list = taskService.createTaskQuery().taskCandidateGroup(group.getId()).list();
//        taskList.addAll(list);
        List<VacTask> vacTaskList = new ArrayList<>();
        for (Task task : taskList) {
            VacTask vacTask = new VacTask();
            vacTask.setId(task.getId());
            vacTask.setName(task.getName());
            vacTask.setCreateTime(task.getCreateTime());
            String instanceId = task.getProcessInstanceId();

            // 流程实例相关信息打包
            ProcessInstance instance
                    = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(instanceId)
                    .singleResult();
            Vacation vac = getVac(instance);
            vacTask.setVac(vac);
            vacTaskList.add(vacTask);
        }
        return vacTaskList;
    }

    /**
     * 审核
     *
     * @param userName 用户名
     * @param vacTask  审核的任务
     * @return 结果
     */
    public Object passAudit(String userName, VacTask vacTask) {
        String taskId = vacTask.getId();
        String result = vacTask.getVac().getResult();
        Map<String, Object> vars = new HashMap<>();
        vars.put("result", result);
        vars.put("auditor", userName);
        vars.put("auditTime", new Date());

        // 设置办理人/如果已经有办理人，抛出异常
        taskService.claim(taskId, userName);
        // 审核通过或拒绝
        taskService.complete(taskId, vars);
        return true;
    }

    /**
     * 我申请过的假
     *
     * @param userName 用户名
     * @return 列表
     */
    public Object myVacRecord(String userName) {
        List<HistoricProcessInstance> hisProInstance
                = historyService.createHistoricProcessInstanceQuery()
                // 请假流程
                .processDefinitionKey(PROCESS_DEFINE_KEY)
                // 流程发起人
                .startedBy(userName)
                // 已完成的
                .finished()
                // 排序等
                .orderByProcessInstanceEndTime().desc().list();

        List<Vacation> vacList = new ArrayList<>();
        for (HistoricProcessInstance hisInstance : hisProInstance) {
            Vacation vacation = new Vacation();
            vacation.setApplyUser(hisInstance.getStartUserId());
            vacation.setApplyTime(hisInstance.getStartTime());
            vacation.setApplyStatus("申请结束");
            // 历史赋值等信息根据实例ID查询
            List<HistoricVariableInstance> varInstanceList
                    = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(hisInstance.getId())
                    .list();
            // 结果打包
            ActivitiUtil.setVars(vacation, varInstanceList);
            vacList.add(vacation);
        }
        return vacList;
    }


    /**
     * 我的审核记录
     *
     * @param userName 用户名
     * @return 列表
     */
    public Object myAuditRecord(String userName) {
        List<HistoricProcessInstance> hisProInstance
                = historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey(PROCESS_DEFINE_KEY)
                // 审核人名称
                .involvedUser(userName)
                // 已完成的实例
                .finished()
                // 排序
                .orderByProcessInstanceEndTime().desc().list();

        List<String> auditTaskNameList = new ArrayList<>();
        auditTaskNameList.add("经理审批");
        auditTaskNameList.add("总监审批");
        List<Vacation> vacList = new ArrayList<>();
        for (HistoricProcessInstance hisInstance : hisProInstance) {

            // 对历史任务实例取值
            List<HistoricTaskInstance> hisTaskInstanceList
                    = historyService.createHistoricTaskInstanceQuery()
                    // 实例ID
                    .processInstanceId(hisInstance.getId())
                    // 处理完成的
                    .processFinished()
                    // 任务待办人/设置时为强制设置
                    .taskAssignee(userName)
                    // 任务名称范围
                    .taskNameIn(auditTaskNameList)
                    // 按历史任务实例结束时间排序
                    .orderByHistoricTaskInstanceEndTime().desc().list();
            boolean isMyAudit = false;
            for (HistoricTaskInstance taskInstance : hisTaskInstanceList) {
                if (taskInstance.getAssignee().equals(userName)) {
                    isMyAudit = true;
                }
            }
            // 如果不是我审批的，跳过
            if (!isMyAudit) {
                continue;
            }
            Vacation vacation = new Vacation();
            vacation.setApplyUser(hisInstance.getStartUserId());
            vacation.setApplyStatus("申请结束");
            vacation.setApplyTime(hisInstance.getStartTime());

            // 历史变量实例查询
            List<HistoricVariableInstance> varInstanceList
                    = historyService.createHistoricVariableInstanceQuery()
                    // 根据实例ID插叙
                    .processInstanceId(hisInstance.getId()).list();
            ActivitiUtil.setVars(vacation, varInstanceList);
            vacList.add(vacation);
        }
        return vacList;
    }
}
